function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1,
$lowercase = true, $engine = 'auto'
) {
- $input = (string)$input;
- if (
- $sourceBase < 2 ||
- $sourceBase > 36 ||
- $destBase < 2 ||
- $destBase > 36 ||
- $sourceBase != (int)$sourceBase ||
- $destBase != (int)$destBase ||
- $pad != (int)$pad ||
- !preg_match(
- "/^[" . substr( '0123456789abcdefghijklmnopqrstuvwxyz', 0, $sourceBase ) . "]+$/i",
- $input
- )
- ) {
- return false;
- }
-
- static $baseChars = array(
- 10 => 'a', 11 => 'b', 12 => 'c', 13 => 'd', 14 => 'e', 15 => 'f',
- 16 => 'g', 17 => 'h', 18 => 'i', 19 => 'j', 20 => 'k', 21 => 'l',
- 22 => 'm', 23 => 'n', 24 => 'o', 25 => 'p', 26 => 'q', 27 => 'r',
- 28 => 's', 29 => 't', 30 => 'u', 31 => 'v', 32 => 'w', 33 => 'x',
- 34 => 'y', 35 => 'z',
-
- '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5,
- '6' => 6, '7' => 7, '8' => 8, '9' => 9, 'a' => 10, 'b' => 11,
- 'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15, 'g' => 16, 'h' => 17,
- 'i' => 18, 'j' => 19, 'k' => 20, 'l' => 21, 'm' => 22, 'n' => 23,
- 'o' => 24, 'p' => 25, 'q' => 26, 'r' => 27, 's' => 28, 't' => 29,
- 'u' => 30, 'v' => 31, 'w' => 32, 'x' => 33, 'y' => 34, 'z' => 35
- );
-
- if ( extension_loaded( 'gmp' ) && ( $engine == 'auto' || $engine == 'gmp' ) ) {
- // Removing leading zeros works around broken base detection code in
- // some PHP versions (see <https://bugs.php.net/bug.php?id=50175> and
- // <https://bugs.php.net/bug.php?id=55398>).
- $result = gmp_strval( gmp_init( ltrim( $input, '0' ) ?: '0', $sourceBase ), $destBase );
- } elseif ( extension_loaded( 'bcmath' ) && ( $engine == 'auto' || $engine == 'bcmath' ) ) {
- $decimal = '0';
- foreach ( str_split( strtolower( $input ) ) as $char ) {
- $decimal = bcmul( $decimal, $sourceBase );
- $decimal = bcadd( $decimal, $baseChars[$char] );
- }
-
- // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
- for ( $result = ''; bccomp( $decimal, 0 ); $decimal = bcdiv( $decimal, $destBase, 0 ) ) {
- $result .= $baseChars[bcmod( $decimal, $destBase )];
- }
- // @codingStandardsIgnoreEnd
-
- $result = strrev( $result );
- } else {
- $inDigits = array();
- foreach ( str_split( strtolower( $input ) ) as $char ) {
- $inDigits[] = $baseChars[$char];
- }
-
- // Iterate over the input, modulo-ing out an output digit
- // at a time until input is gone.
- $result = '';
- while ( $inDigits ) {
- $work = 0;
- $workDigits = array();
-
- // Long division...
- foreach ( $inDigits as $digit ) {
- $work *= $sourceBase;
- $work += $digit;
-
- if ( $workDigits || $work >= $destBase ) {
- $workDigits[] = (int)( $work / $destBase );
- }
- $work %= $destBase;
- }
-
- // All that division leaves us with a remainder,
- // which is conveniently our next output digit.
- $result .= $baseChars[$work];
-
- // And we continue!
- $inDigits = $workDigits;
- }
-
- $result = strrev( $result );
- }
-
- if ( !$lowercase ) {
- $result = strtoupper( $result );
- }
-
- return str_pad( $result, $pad, '0', STR_PAD_LEFT );
+ return Wikimedia\base_convert( $input, $sourceBase, $destBase, $pad, $lowercase, $engine );
}
/**
+++ /dev/null
-<?php
-/**
- * @group GlobalFunctions
- * @covers ::wfBaseConvert
- */
-class WfBaseConvertTest extends MediaWikiTestCase {
- public static function provideSingleDigitConversions() {
- return array(
- // 2 3 5 8 10 16 36
- array( '0', '0', '0', '0', '0', '0', '0' ),
- array( '1', '1', '1', '1', '1', '1', '1' ),
- array( '10', '2', '2', '2', '2', '2', '2' ),
- array( '11', '10', '3', '3', '3', '3', '3' ),
- array( '100', '11', '4', '4', '4', '4', '4' ),
- array( '101', '12', '10', '5', '5', '5', '5' ),
- array( '110', '20', '11', '6', '6', '6', '6' ),
- array( '111', '21', '12', '7', '7', '7', '7' ),
- array( '1000', '22', '13', '10', '8', '8', '8' ),
- array( '1001', '100', '14', '11', '9', '9', '9' ),
- array( '1010', '101', '20', '12', '10', 'a', 'a' ),
- array( '1011', '102', '21', '13', '11', 'b', 'b' ),
- array( '1100', '110', '22', '14', '12', 'c', 'c' ),
- array( '1101', '111', '23', '15', '13', 'd', 'd' ),
- array( '1110', '112', '24', '16', '14', 'e', 'e' ),
- array( '1111', '120', '30', '17', '15', 'f', 'f' ),
- array( '10000', '121', '31', '20', '16', '10', 'g' ),
- array( '10001', '122', '32', '21', '17', '11', 'h' ),
- array( '10010', '200', '33', '22', '18', '12', 'i' ),
- array( '10011', '201', '34', '23', '19', '13', 'j' ),
- array( '10100', '202', '40', '24', '20', '14', 'k' ),
- array( '10101', '210', '41', '25', '21', '15', 'l' ),
- array( '10110', '211', '42', '26', '22', '16', 'm' ),
- array( '10111', '212', '43', '27', '23', '17', 'n' ),
- array( '11000', '220', '44', '30', '24', '18', 'o' ),
- array( '11001', '221', '100', '31', '25', '19', 'p' ),
- array( '11010', '222', '101', '32', '26', '1a', 'q' ),
- array( '11011', '1000', '102', '33', '27', '1b', 'r' ),
- array( '11100', '1001', '103', '34', '28', '1c', 's' ),
- array( '11101', '1002', '104', '35', '29', '1d', 't' ),
- array( '11110', '1010', '110', '36', '30', '1e', 'u' ),
- array( '11111', '1011', '111', '37', '31', '1f', 'v' ),
- array( '100000', '1012', '112', '40', '32', '20', 'w' ),
- array( '100001', '1020', '113', '41', '33', '21', 'x' ),
- array( '100010', '1021', '114', '42', '34', '22', 'y' ),
- array( '100011', '1022', '120', '43', '35', '23', 'z' )
- );
- }
-
- /**
- * @dataProvider provideSingleDigitConversions
- */
- public function testDigitToBase2( $base2, $base3, $base5, $base8, $base10, $base16, $base36 ) {
- $this->assertSame( $base2, wfBaseConvert( $base3, '3', '2' ) );
- $this->assertSame( $base2, wfBaseConvert( $base5, '5', '2' ) );
- $this->assertSame( $base2, wfBaseConvert( $base8, '8', '2' ) );
- $this->assertSame( $base2, wfBaseConvert( $base10, '10', '2' ) );
- $this->assertSame( $base2, wfBaseConvert( $base16, '16', '2' ) );
- $this->assertSame( $base2, wfBaseConvert( $base36, '36', '2' ) );
- }
-
- /**
- * @dataProvider provideSingleDigitConversions
- */
- public function testDigitToBase3( $base2, $base3, $base5, $base8, $base10, $base16, $base36 ) {
- $this->assertSame( $base3, wfBaseConvert( $base2, '2', '3' ) );
- $this->assertSame( $base3, wfBaseConvert( $base5, '5', '3' ) );
- $this->assertSame( $base3, wfBaseConvert( $base8, '8', '3' ) );
- $this->assertSame( $base3, wfBaseConvert( $base10, '10', '3' ) );
- $this->assertSame( $base3, wfBaseConvert( $base16, '16', '3' ) );
- $this->assertSame( $base3, wfBaseConvert( $base36, '36', '3' ) );
- }
-
- /**
- * @dataProvider provideSingleDigitConversions
- */
- public function testDigitToBase5( $base2, $base3, $base5, $base8, $base10, $base16, $base36 ) {
- $this->assertSame( $base5, wfBaseConvert( $base2, '2', '5' ) );
- $this->assertSame( $base5, wfBaseConvert( $base3, '3', '5' ) );
- $this->assertSame( $base5, wfBaseConvert( $base8, '8', '5' ) );
- $this->assertSame( $base5, wfBaseConvert( $base10, '10', '5' ) );
- $this->assertSame( $base5, wfBaseConvert( $base16, '16', '5' ) );
- $this->assertSame( $base5, wfBaseConvert( $base36, '36', '5' ) );
- }
-
- /**
- * @dataProvider provideSingleDigitConversions
- */
- public function testDigitToBase8( $base2, $base3, $base5, $base8, $base10, $base16, $base36 ) {
- $this->assertSame( $base8, wfBaseConvert( $base2, '2', '8' ) );
- $this->assertSame( $base8, wfBaseConvert( $base3, '3', '8' ) );
- $this->assertSame( $base8, wfBaseConvert( $base5, '5', '8' ) );
- $this->assertSame( $base8, wfBaseConvert( $base10, '10', '8' ) );
- $this->assertSame( $base8, wfBaseConvert( $base16, '16', '8' ) );
- $this->assertSame( $base8, wfBaseConvert( $base36, '36', '8' ) );
- }
-
- /**
- * @dataProvider provideSingleDigitConversions
- */
- public function testDigitToBase10( $base2, $base3, $base5, $base8, $base10, $base16, $base36 ) {
- $this->assertSame( $base10, wfBaseConvert( $base2, '2', '10' ) );
- $this->assertSame( $base10, wfBaseConvert( $base3, '3', '10' ) );
- $this->assertSame( $base10, wfBaseConvert( $base5, '5', '10' ) );
- $this->assertSame( $base10, wfBaseConvert( $base8, '8', '10' ) );
- $this->assertSame( $base10, wfBaseConvert( $base16, '16', '10' ) );
- $this->assertSame( $base10, wfBaseConvert( $base36, '36', '10' ) );
- }
-
- /**
- * @dataProvider provideSingleDigitConversions
- */
- public function testDigitToBase16( $base2, $base3, $base5, $base8, $base10, $base16, $base36 ) {
- $this->assertSame( $base16, wfBaseConvert( $base2, '2', '16' ) );
- $this->assertSame( $base16, wfBaseConvert( $base3, '3', '16' ) );
- $this->assertSame( $base16, wfBaseConvert( $base5, '5', '16' ) );
- $this->assertSame( $base16, wfBaseConvert( $base8, '8', '16' ) );
- $this->assertSame( $base16, wfBaseConvert( $base10, '10', '16' ) );
- $this->assertSame( $base16, wfBaseConvert( $base36, '36', '16' ) );
- }
-
- /**
- * @dataProvider provideSingleDigitConversions
- */
- public function testDigitToBase36( $base2, $base3, $base5, $base8, $base10, $base16, $base36 ) {
- $this->assertSame( $base36, wfBaseConvert( $base2, '2', '36' ) );
- $this->assertSame( $base36, wfBaseConvert( $base3, '3', '36' ) );
- $this->assertSame( $base36, wfBaseConvert( $base5, '5', '36' ) );
- $this->assertSame( $base36, wfBaseConvert( $base8, '8', '36' ) );
- $this->assertSame( $base36, wfBaseConvert( $base10, '10', '36' ) );
- $this->assertSame( $base36, wfBaseConvert( $base16, '16', '36' ) );
- }
-
- public function testLargeNumber() {
- $this->assertSame( '1100110001111010000000101110100', wfBaseConvert( 'sd89ys', 36, 2 ) );
- $this->assertSame( '11102112120221201101', wfBaseConvert( 'sd89ys', 36, 3 ) );
- $this->assertSame( '12003102232400', wfBaseConvert( 'sd89ys', 36, 5 ) );
- $this->assertSame( '14617200564', wfBaseConvert( 'sd89ys', 36, 8 ) );
- $this->assertSame( '1715274100', wfBaseConvert( 'sd89ys', 36, 10 ) );
- $this->assertSame( '663d0174', wfBaseConvert( 'sd89ys', 36, 16 ) );
- }
-
- public static function provideNumbers() {
- $x = array();
- $chars = '0123456789abcdefghijklmnopqrstuvwxyz';
- for ( $i = 0; $i < 50; $i++ ) {
- $base = mt_rand( 2, 36 );
- $len = mt_rand( 10, 100 );
-
- $str = '';
- for ( $j = 0; $j < $len; $j++ ) {
- $str .= $chars[mt_rand( 0, $base - 1 )];
- }
-
- $x[] = array( $base, $str );
- }
-
- return $x;
- }
-
- /**
- * @dataProvider provideNumbers
- */
- public function testIdentity( $base, $number ) {
- $this->assertSame( $number, wfBaseConvert( $number, $base, $base, strlen( $number ) ) );
- }
-
- public function testInvalid() {
- $this->assertFalse( wfBaseConvert( '101', 1, 15 ) );
- $this->assertFalse( wfBaseConvert( '101', 15, 1 ) );
- $this->assertFalse( wfBaseConvert( '101', 37, 15 ) );
- $this->assertFalse( wfBaseConvert( '101', 15, 37 ) );
- $this->assertFalse( wfBaseConvert( 'abcde', 10, 11 ) );
- $this->assertFalse( wfBaseConvert( '12930', 2, 10 ) );
- $this->assertFalse( wfBaseConvert( '101', 'abc', 15 ) );
- $this->assertFalse( wfBaseConvert( '101', 15, 'abc' ) );
- }
-
- public function testPadding() {
- $number = "10101010101";
- $this->assertSame(
- strlen( $number ) + 5,
- strlen( wfBaseConvert( $number, 2, 2, strlen( $number ) + 5 ) )
- );
- $this->assertSame(
- strlen( $number ),
- strlen( wfBaseConvert( $number, 2, 2, strlen( $number ) - 5 ) )
- );
- }
-
- public function testLeadingZero() {
- $this->assertSame( '24', wfBaseConvert( '010', 36, 16 ) );
- $this->assertSame( '37d4', wfBaseConvert( '0b10', 36, 16 ) );
- $this->assertSame( 'a734', wfBaseConvert( '0x10', 36, 16 ) );
- }
-}